/*****************************************************************************/
/**
 *  @file   DataSet.cpp
 *  @author Naohisa Sakamoto
 */
/*----------------------------------------------------------------------------
 *
 *  Copyright (c) Visualization Laboratory, Kyoto University.
 *  All rights reserved.
 *  See http://www.viz.media.kyoto-u.ac.jp/kvs/copyright/ for details.
 *
 *  $Id$
 */
/*****************************************************************************/
#include "DataSet.h"
#include <kvs/Message>
#include <kvs/Directory>
#include <kvs/FileList>
#include <kvs/Math>
#include <kvs/StructuredVolumeImporter>
#include <kvs/PointImporter>


namespace
{

DataSet::FilenameList ReadFilenames( const std::string& dirname, const std::string& extension )
{
    DataSet::FilenameList filenames;

    kvs::Directory directory( dirname );
    const kvs::FileList files = directory.fileList();
    for ( size_t i = 0; i < files.size(); i++ )
    {
        if ( files[i].extension() == extension )
        {
            std::cout << "Reading filename: " << files[i].filePath() << std::endl;

            filenames.push_back( files[i].filePath() );
        }
    }

    return filenames;
}

};

void DataSet::incrementTimeStep( const bool loop )
{
    const size_t start = 0;
    const size_t end = this->numberOfTimeSteps() - 1;
    if ( m_time_step < end ) m_time_step++;
    else { if ( loop ) m_time_step = start; }
}

void DataSet::decrementTimeStep( const bool loop )
{
    const size_t start = 0;
    const size_t end = this->numberOfTimeSteps() - 1;
    if ( m_time_step > start ) m_time_step--;
    else { if ( loop ) m_time_step = end; }
}

void DataSet::setTimeStep( const size_t time_step )
{
    const size_t start = 0;
    const size_t end = this->numberOfTimeSteps() - 1;
    m_time_step = kvs::Math::Clamp( time_step, start, end );
}

bool DataSet::load( const std::string& volume_dirname, const std::string& particle_dirname )
{
    m_time_step = 0;

    m_volume_filenames = ::ReadFilenames( volume_dirname, "fld" );
    if ( m_volume_filenames.size() == 0 )
    {
        kvsMessageError("Not found any volume data files.");
        return false;
    }

    m_particle_filenames = ::ReadFilenames( particle_dirname, "kvsml" );
    if ( m_particle_filenames.size() == 0 )
    {
        kvsMessageError("Not found any particle data files.");
        return false;
    }

    if ( m_volume_filenames.size() != m_particle_filenames.size() )
    {
        kvsMessageError("Not corresponded the number of files between the volume and particle data.");
        return false;
    }

    return this->loadParticles() && this->loadVolume();
}

bool DataSet::loadVolume()
{
    std::string filename = m_volume_filenames[m_time_step];
    if ( filename == m_loaded_volume_filename ) return true;

    std::cout << "Importing volume: " << filename << " ... " << std::flush;

    m_volume = Volume( new kvs::StructuredVolumeImporter( filename ) );
    if ( !m_volume ) return false;

    std::cout << "done." << std::endl;

    m_loaded_volume_filename = filename;
    m_volume->setName( "Volume" );

    if ( this->particle().get() )
    {
        m_volume->setMinMaxObjectCoords( this->particle()->minObjectCoord(), this->particle()->maxObjectCoord() );
        m_volume->setMinMaxExternalCoords( this->particle()->minExternalCoord(), this->particle()->maxExternalCoord() );
    }

    // TEST IMPLEMENTATION
    m_bounds.ranges.clear();
    kvs::Vec3ui resolution = m_volume->resolution();
    size_t ndivs = 15;
    size_t div_dimx = resolution.x() / ndivs;
    size_t div_dimy = resolution.y() / ndivs;
    size_t div_dimz = resolution.z() / ndivs;
    for ( size_t k = 0; k < ndivs; k++ )
    {
        for ( size_t j = 0; j < ndivs; j++ )
        {
            for ( size_t i = 0; i < ndivs; i++ )
            {
                const size_t I = i + 1;
                const size_t J = j + 1;
                const size_t K = k + 1;
                const kvs::Vec3 min( div_dimx * i, div_dimy * j, div_dimz * k );
                const kvs::Vec3 max( div_dimx * I, div_dimy * J, div_dimz * K );
                Range range; range.min = min; range.max = max;
                m_bounds.ranges.push_back( range );
            }
        }
    }

    return true;
}

bool DataSet::loadParticles()
{
    for ( size_t i = 0; i < m_particle_filenames.size(); i++ )
    {
        std::cout << "Importing particle: " << m_particle_filenames[i] << " ... " << std::flush;

        Particle particle = Particle( new kvs::PointImporter( m_particle_filenames[i] ) );
        if ( particle )
        {
            particle->setName( "Particle" );

            if ( this->volume().get() )
            {
                particle->setMinMaxObjectCoords( this->volume()->minObjectCoord(), this->volume()->maxObjectCoord() );
                particle->setMinMaxExternalCoords( this->volume()->minExternalCoord(), this->volume()->maxExternalCoord() );
            }

            m_particles.push_back( particle );
            std::cout << "done.";

        }
        std::cout << std::endl;
    }

    if ( m_particle_filenames.size() != m_particles.size() ) return false;

    return true;
}
